#include<iostream>
#include<queue>
#include<pthread.h>

//默认的队列的大小
int gcap=5;

template<class T>
class blockQueue
{
public:
    //构造函数
    blockQueue(int cap=gcap)
    :_cap(cap)
    {
        //初始化锁和条件变量
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_consumerCond,nullptr);
        pthread_cond_init(&_producerCond,nullptr);
    }
    //析构函数
    ~blockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_consumerCond);
        pthread_cond_destroy(&_producerCond);
    }

    //判断队列是否满
    bool isFull(){  return _cap==_q.size();  }

    //判断队列是否为空
    bool isEmpty(){  return _q.empty();  }

    //放数据
    void push(T&in)
    {
        //访问临界区

        //加锁
        pthread_mutex_lock(&_mutex);

        //判断队列是否满
        while(isFull())
        {
            //队列为满说明不需要再生产，开始等待
            //在生产者条件变量上等待，同时还需要解锁
            pthread_cond_wait(&_producerCond,&_mutex);
            //唤醒后再wait处继续运行，同时加锁
        }

        //放入数据
        _q.push(in);
        //有生产数据就可以唤醒消费者
        pthread_cond_signal(&_consumerCond);
        //解锁
        pthread_mutex_unlock(&_mutex);
    }

    //取数据
    void pop(T*out)
    {
        //访问临界区加锁
        pthread_mutex_lock(&_mutex);

        //判断队列是否为空
        while(isEmpty())
        {
            //为空则不需要再拿数据
            //在消费者条件变量上等待
            pthread_cond_wait(&_consumerCond,&_mutex);
        }
        //取出数据
        *out=_q.front();
        _q.pop();

        //唤醒生产者
        pthread_cond_signal(&_producerCond);
        pthread_mutex_unlock(&_mutex);

        //访问结束，解锁
        pthread_mutex_unlock(&_mutex);
    }

private:
    std::queue<T> _q;//存放资源的队列
    int _cap;//队列的容量
    pthread_mutex_t _mutex;//互斥锁
    pthread_cond_t _consumerCond;//消费者的条件变量，当队列空时，wait
    pthread_cond_t _producerCond;//生产者的条件变量，当队列满时，wait
};